package Servises;

import java.util.HashMap;
import java.util.LinkedList;

import model.CustomPoint;
import model.Element;
import model.GameInfo;
import model.Movie;
import model.MovieEvent;
import model.Result;
import model.UrlFile;
import model.CustomPoint.SizeF;
import model.EventProperties.ClickEventProperties;
import model.EventProperties.MotionEventProperties;
import model.EventProperties.MoveablePictureEventProperties;
import model.EventProperties.PushMsgEventProperties;
import model.EventProperties.ReadFladEventProperties;
import model.Interface.IeventProperties;
import model.Interface.IresultProperties;
import model.ResultProperties.ChangeGlobleElementTextResultProprties;
import model.ResultProperties.HidePictureResultProperties;
import model.ResultProperties.KillEventResultProperties;
import model.ResultProperties.MoveToMovieResultProperties;
import model.ResultProperties.PlaySoundProperties;
import model.ResultProperties.SetFlagResultProperties;
import model.ResultProperties.ShowPictureResultProperties;
import model.ResultProperties.StartActivityProperties;
import model.ResultProperties.StopSoundResultProperties;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import Enums.EventType;
import Enums.FlagOptions;
import Enums.MotionType;
import Enums.ResultAction;
import Enums.Shape;
import Enums.UiElement;
import android.graphics.Color;
import android.graphics.PointF;
import android.graphics.Rect;
import android.util.Log;

public class MySaxHandler extends DefaultHandler {

	private boolean inStartingMovieId;
	private GameInfo parsedGameInfo;
	private boolean inResultsYes;
	private boolean inResultsNo;
	private boolean inEndResult;
	private boolean inTimeFrameStart;
	private boolean inTimeFrameEnd;

	// Current Movie data
	private Movie currentMovie;
	private boolean inMovie;
	LinkedList<Result> endOfMovieResults;
	LinkedList<Result> resultYesResults;
	LinkedList<Result> resultNoResults;
	private MovieEvent currentEvent;

	@Override
	public void startDocument() throws SAXException {
		parsedGameInfo = new GameInfo();
	}

	@Override
	public void endDocument() throws SAXException {
		// Do some finishing work if needed
	}

	@Override
	public void startElement(String namespaceURI, String localName,
			String qName, Attributes atts) throws SAXException {

		Log.w("Saxer", localName);
		try {
			if (localName.equals("StartingMovieId")) {
				inStartingMovieId = true;
			} else if (localName.equals("GameInfo")) {
				SizeF editorScreenSize = new SizeF();
				editorScreenSize.height = Float.parseFloat(atts
						.getValue("screenHeight"));
				editorScreenSize.width = Float.parseFloat(atts
						.getValue("screenWidth"));
				CustomPoint.setEditorScreenSize(editorScreenSize);
			} else if (localName.equals("Flag")) {
				parsedGameInfo.flags.put(atts.getValue("name"), Boolean
						.parseBoolean(atts.getValue("initValue")));
				parsedGameInfo.flagsInitialValue.put(atts.getValue("name"),
						Boolean.parseBoolean(atts.getValue("initValue")));
			} else if (localName.equals("EndResult")) {
				inEndResult = true;
			} else if (localName.equals("ResultsYes")) {
				inResultsYes = true;
			} else if (localName.equals("ResultsNo")) {
				inResultsNo = true;
			} else if (localName.equals("Movie")) {
				inMovie = true;
				int movieId = Integer.parseInt(atts.getValue("id"));
				String movieUrl = atts.getValue("url");
				// String movieFileName = atts.getValue("fileName");
				// String movieFileSuffix = atts.getValue("fileSuffix");
				boolean movieIsOnline = Boolean.parseBoolean(atts
						.getValue("isOnline"));
				currentMovie = new Movie(movieId, movieUrl, movieIsOnline);
				currentMovie.events = new HashMap<Integer, MovieEvent>();
				endOfMovieResults = new LinkedList<Result>();
			} else if (localName.equals("Event")) {
				currentEvent = parseEvent(atts);
				resultYesResults = new LinkedList<Result>();
				resultNoResults = new LinkedList<Result>();
			} else if (localName.equals("Result")) {
				Result tmpResult = parseResult(atts);
				if (inResultsNo) {
					resultNoResults.add(tmpResult);
				} else if (inResultsYes) {
					resultYesResults.add(tmpResult);
				} else if (inEndResult) {
					endOfMovieResults.add(tmpResult);
				}
			} else if (localName.equals("Start")) {
				inTimeFrameStart = true;
			} else if (localName.equals("End")) {
				inTimeFrameEnd = true;
			}
		} catch (Exception e) {
			Log.w("InTouchTv", "XML Error: " + e.getLocalizedMessage());
			return;
		}
	}

	@Override
	public void endElement(String namespaceURI, String localName, String qName)
			throws SAXException {
		Log.w("InTouchTV", localName);
		try {
			if (localName.equals("Movie")) {
				currentMovie.endOfMovieResult = new Result[endOfMovieResults
						.size()];
				currentMovie.endOfMovieResult = endOfMovieResults
						.toArray(currentMovie.endOfMovieResult);
				parsedGameInfo.movies.put(currentMovie.getId(), currentMovie);
				inMovie = false;
			} else if (localName.equals("EndResult")) {
				inEndResult = false;
			} else if (localName.equals("ResultsYes")) {
				inResultsYes = false;
			} else if (localName.equals("ResultsNo")) {
				inResultsNo = false;
			} else if (localName.equals("Event")) {
				currentEvent.resultNo = new Result[resultNoResults.size()];
				currentEvent.resultNo = resultNoResults
						.toArray(currentEvent.resultNo);
				currentEvent.resultYes = new Result[resultYesResults.size()];
				currentEvent.resultYes = resultYesResults
						.toArray(currentEvent.resultYes);
				currentMovie.events.put(currentEvent.id, currentEvent);
			} else if (localName.equals("Start")) {
				inTimeFrameStart = false;
			} else if (localName.equals("End")) {
				inTimeFrameEnd = false;
			} else if (localName.equals("StartingMovieId")) {
				inStartingMovieId = false;
			}
		} catch (Exception e) {
			Log.w("InTouchTv", "XML Error: " + e.getLocalizedMessage());
			return;
		}

	}

	/**
	 * Gets be called on the following structure: <tag>characters</tag>
	 */
	@Override
	public void characters(char ch[], int start, int length) {
		Log.w("Saxer", new String(ch));
		if (inStartingMovieId) {
			String startMovieIdStr = new String(ch);
			parsedGameInfo.startMovieId = Integer.parseInt(startMovieIdStr
					.trim());
		} else if (inTimeFrameEnd) {
			currentEvent.endTime = Long.parseLong(new String(ch).trim());
		} else if (inTimeFrameStart) {
			currentEvent.startTime = Long.parseLong(new String(ch).trim());
		}
	}

	public GameInfo getParsedData() {
		return parsedGameInfo;
	}

	// ///////////////////////////////////MovieEvent///////////////////////////////////////

	public MovieEvent parseEvent(Attributes atts) {
		int id = Integer.parseInt(atts.getValue("id"));
		EventType type = EventType.valueOf(atts.getValue("type"));

		IeventProperties prop = null;

		switch (type) {
		case click:
			prop = getClickEventPeoprties(atts);
			break;

		case voice:
			break;

		case pushMsg:
			prop = getPushMsgProperties(atts);
			break;

		case motion:
			prop = getMotionProperties(atts);
			break;

		case tuochScreen:
			prop = getClickEventPeoprties(atts);
			break;

		case keybord:
			break;

		case showMovablePicture:
			prop = getMovablePictureProperties(atts);
			break;

		case readFlag:
			prop = getReadFlagProperties(atts);
			break;
		}

		return new MovieEvent(id, type, prop);
	}

	private static IeventProperties getReadFlagProperties(Attributes atts) {
		String flagName = atts.getValue("name");

		return new ReadFladEventProperties(flagName);
	}

	private static IeventProperties getPushMsgProperties(Attributes atts) {
		String msgName = atts.getValue("name");

		return new PushMsgEventProperties(msgName);
	}

	private static IeventProperties getMovablePictureProperties(Attributes atts) {
		UrlFile url = getUrlFile(atts);
		Rect primeryLocation = getRectLocation(atts, "primLocationTopLeft",
				"primLocationBottomRight");
		Rect SecLocation = getRectLocation(atts, "secLocationTopLeft",
				"secLocationBottomRight");
		int numOfFrames = Integer.parseInt(atts.getValue("numOfFrames"));

		return new MoveablePictureEventProperties(primeryLocation, SecLocation,
				url, numOfFrames);
	}

	private static IeventProperties getMotionProperties(Attributes atts) {
		MotionType type = MotionType.valueOf(atts.getValue("motionType"));
		return new MotionEventProperties(type);
	}

	private static IeventProperties getClickEventPeoprties(Attributes atts) {

		Boolean isVisible = Boolean.parseBoolean(atts.getValue("isVisible"));
		Boolean isShowClickEffect = Boolean.parseBoolean(atts
				.getValue("isShowClickEffect"));
		String colorSt = atts.getValue("clickEffectColor").trim();
		int clickEffectColor = getColor(colorSt);
		UrlFile url = getUrlFile(atts);

		return new ClickEventProperties(getElement(atts), isVisible,
				isShowClickEffect, clickEffectColor, url);
	}

	private static Element getElement(Attributes atts) {
		String colorSt;
		Rect rect = getRectLocation(atts);
		UiElement uiElement = UiElement.valueOf(atts.getValue("elementType"));
		colorSt = atts.getValue("color").trim();
		int color = getColor(colorSt);
		String text = atts.getValue("text");
		// Shape shape =
		// Shape.valueOf(propNode.getAttributes().getNamedItem("shape").getNodeValue());
		Shape shape = Shape.rectangle;
		Boolean isFlickering = Boolean.parseBoolean(atts
				.getValue("isFlickering"));
		return new Element(rect, uiElement, color, text, shape, isFlickering);
	}

	private static int getColor(String color) {

		int a = Integer.parseInt(color.substring(color.lastIndexOf(",") + 1,
				color.length()));
		int r = Integer.parseInt(color.substring(0, color.indexOf(",")));
		color = color.substring(color.indexOf(",") + 1);
		int g = Integer.parseInt(color.substring(0, color.indexOf(",")));
		color = color.substring(color.indexOf(",") + 1);
		int b = Integer.parseInt(color.substring(0, color.indexOf(",")));

		return Color.argb(a, r, g, b);
	}

	// ///////////////////////////////Result/////////////////////////////////////////////

	public Result parseResult(Attributes atts) {
		ResultAction action = ResultAction.valueOf(atts.getValue("type"));
		Log.d("Saxer", atts.getValue("type"));
		String checkFlag = atts.getValue("checkFlag");

		IresultProperties prop;
		switch (action) {
		case startActivity: {
			String activityName = atts.getValue("name");
			prop = new StartActivityProperties(activityName);
			break;
		}
		case killEvent: {
			int eventId = Integer.parseInt(atts.getValue("eventId"));
			prop = new KillEventResultProperties(eventId);
			break;

		}
		case setFlag: {
			String flagName = atts.getValue("name");
			String flagValueString = atts.getValue("value");
			FlagOptions flagValue = FlagOptions.valueOf(flagValueString);

			prop = new SetFlagResultProperties(flagName, flagValue);

			break;
		}
		case moveToMovie: {
			int id = Integer.parseInt(atts.getValue("movieId"));
			int time = Integer.parseInt(atts.getValue("time"));
			// For now we don't support smooth trans since it
			// drains all the memory
			boolean smoothTrans = false;
			prop = new MoveToMovieResultProperties(id, time, smoothTrans);
			break;
		}
		case changeGlobalElementText: {
			int id = Integer.parseInt(atts.getValue("elementId"));
			String text = atts.getValue("text");
			prop = new ChangeGlobleElementTextResultProprties(id, text);
			break;
		}

		case playAudio: {
			Boolean isMoviePaused = Boolean.parseBoolean(atts
					.getValue("isMoviePaused"));
			prop = new PlaySoundProperties(getUrlFile(atts), isMoviePaused);
			String loop = atts.getValue("loop");
			if (loop != null && loop.equals("true")) {
				((PlaySoundProperties) prop).loop = true;
			}
			break;
		}
		case initFlags: {
			prop = null;
			break;
		}
		case showPicture: {
			int duration = Integer.parseInt(atts.getValue("duration"));

			Boolean isFlickering = Boolean.parseBoolean(atts
					.getValue("isFlickering"));

			Boolean isMoviePaused = Boolean.parseBoolean(atts
					.getValue("isMoviePaused"));

			Rect rect = getRectLocation(atts);

			int numOfFrames = Integer.parseInt(atts.getValue("numOfFrames"));

			prop = new ShowPictureResultProperties(getUrlFile(atts), duration,
					isFlickering, rect, isMoviePaused, numOfFrames);
			break;
		}
		case stopSound: {
			prop = new StopSoundResultProperties(getUrlFile(atts));
			break;
		}
		case hidePicture: {
			prop = new HidePictureResultProperties(getUrlFile(atts));
			break;
		}
		default:
			prop = null;
			break;
		}
		return new Result(action, prop, checkFlag);
	}

	private static UrlFile getUrlFile(Attributes atts) {
		String url = atts.getValue("url");
		String movieFileName = atts.getValue("fileName");
		String fileSuffix = atts.getValue("fileSuffix");
		return new UrlFile(url, movieFileName, fileSuffix);
	}

	private static Rect getRectLocation(Attributes atts) {
		return getRectLocation(atts, "locationTopLeft", "locationBottomRight");
	}

	private static Rect getRectLocation(Attributes atts, String topLeftAttName,
			String bottemAttRightName) {
		String locationTopLeft = atts.getValue(topLeftAttName);
		String locationBottomRight = atts.getValue(bottemAttRightName);
		CustomPoint[] rect = new CustomPoint[2];
		rect[0] = getScreenLocation(locationTopLeft);
		rect[1] = getScreenLocation(locationBottomRight);

		int p1 = (int) Math.floor(rect[0].getPoint().x);
		int p2 = (int) Math.floor(rect[0].getPoint().y);
		int p3 = (int) Math.floor(rect[1].getPoint().x);
		int p4 = (int) Math.floor(rect[1].getPoint().y);

		return new Rect(p1, p2, p3, p4);
	}

	private static CustomPoint getScreenLocation(String location) {
		return new CustomPoint(new PointF(Float.parseFloat(location.substring(
				0, location.indexOf(","))), Float.parseFloat(location
				.substring(location.indexOf(",") + 1, location.length()))));
	}

}
